package com.hyq.learn.api.client;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Stopwatch;
import com.hyq.learn.common.exception.SvcException;
import com.hyq.learn.common.exception.errorcode.CommonErrorCode;
import com.hyq.learn.common.util.LowCameCaseJsonUtil;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author heyuqin
 * @date 2024/9/11 11:18
 */
@Component
public class CommonClient {

    protected final static Logger LOGGER = LoggerFactory.getLogger(CommonClient.class);

    @Resource(name = "commonRestTemplate")
    private RestTemplate restTemplate;

    @Nullable
    public <R> R doRequest(HttpMethod httpMethod, String url, TypeReference<R> typeReference, @Nullable Object request, @Nullable HttpHeaders httpHeaders) {
        if (Objects.isNull(httpHeaders)) {
            httpHeaders = buildHeader();
        }
        String requestBody = null;
        if (request != null) {
            if (request instanceof String) {
                requestBody = request.toString();
            } else {
                requestBody = LowCameCaseJsonUtil.toJson(request);
            }
        }
        HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, httpHeaders);
        Stopwatch stopwatch = Stopwatch.createStarted();
        String responseString = null;
        HttpStatusCode httpStatus = null;

        try {
            ResponseEntity<String> exchange = restTemplate.exchange(url, httpMethod, httpEntity, String.class);
            responseString = exchange.getBody();
            httpStatus = exchange.getStatusCode();
            if (StringUtils.isBlank(responseString)) {
                return null;
            }
            return LowCameCaseJsonUtil.fromJson(responseString, typeReference);
        } catch (Exception e) {
            if (e instanceof RestClientResponseException exception) {
                responseString = exception.getResponseBodyAsString();
                httpStatus = exception.getStatusCode();
            }
            throw new SvcException(CommonErrorCode.PARTNER_SERVICE_UNAVAILABLE_ERROR, responseString, e);
        } finally {
            LOGGER.info("request url {} elapsed time {}ms request body is {} response status is {} body is {}",
                    url, stopwatch.elapsed(TimeUnit.MILLISECONDS), requestBody, httpStatus, responseString);
        }
    }

    protected HttpHeaders buildHeader() {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        httpHeaders.setAccept(List.of(MediaType.APPLICATION_JSON));
        return httpHeaders;
    }

}
